package lex.dm.ui.dt;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.sql.Connection;
import java.sql.SQLException;

import javax.swing.*;
import javax.swing.border.TitledBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import org.lex.swing.ActionBuilder;
import org.lex.utils.Pair;

import lex.dm.DTree;
import lex.dm.utils.DBUtils;
import lex.dm.utils.FieldInfo;

public class DataSetSelector extends JDialog {
	private JPanel pane = null;
	private JLabel tableLabel = null;
	private JComboBox tableComboBox = null;
	private JScrollPane fieldScrollPane = null;
	private JTable fieldTable = null;
	private JLabel classLabel = null;
	private JComboBox classComboBox = null;
	private JPanel buttonsPane = null;
	private JButton okButton = null;
	private JScrollPane sqlScrollPane = null;
	private JTextArea sqlTextArea = null;
	// ------------------------------
	private FieldsTableModel tableModel = new FieldsTableModel();
	private final DTree app = DTree.getApplication();
	private JPanel fieldPane = null;
	private JPanel sqlPane = null;

	public static String getSQL(Window root) {
		DataSetSelector d = new DataSetSelector(root);
		d.setLocationRelativeTo(root);
		d.setTitle("Choose Training Set...");
		d.setCatalog(null);
		d.setVisible(true);
		return d.getSQL();
	}

	public DataSetSelector(Window root) {
		super(root);
		initialize();
	}

	private StringBuilder buf = new StringBuilder();

	/**
	 * CLASS �е���ݱ������������, ��ȡ��ʱ����Ҫע��
	 * 
	 * @return
	 */
	public String getSQL() {
		buf.setLength(0);
		buf.append("select ");
		String classField = this.getClassComboBox().getSelectedItem().toString();
		String[] fields = this.tableModel.getSelectedFields();
		for (int i = 0, n = fields.length; i < n; i++) {
			if (false == classField.equals(fields[i])) {
				buf.append(fields[i]);
				buf.append(", ");
			}
		}
		buf.append(classField);
		buf.append(" from ");
		buf.append(this.getTableComboBox().getSelectedItem().toString());
		return buf.toString();
	}

	public void setCatalog( final String catalog )
	{
		new SwingWorker<Pair<String[], FieldInfo[]>, Void>(){
			@Override
			protected Pair<String[], FieldInfo[]> doInBackground() throws Exception
			{
				Connection con = DTree.getApplication().getConnection();
				String[] tables = DBUtils.getTableNames( con, catalog ).toArray( new String[0] );
				FieldInfo[] fields = DBUtils.getFields( con, catalog, tables[0] ).toArray(
					new FieldInfo[0] );
				return Pair.wrap( tables, fields );
			}

			@Override
			protected void done()
			{
				try
				{
					Pair<String[], FieldInfo[]> p = this.get();
					getTableComboBox().setModel( new DefaultComboBoxModel( p.first() ) );
					getClassComboBox().setModel( new DefaultComboBoxModel( p.second() ) );
					tableModel.setContent( p.second() );
				}
				catch( Exception e )
				{
					e.printStackTrace();
				}
				setSelectAll( true );
				updateSQL();
			}
		}.execute();
	}

	public void setSelectedTable(String table) {
		try {
			FieldInfo[] fields = DBUtils.getFields(app.getConnection(), null, table).toArray(new FieldInfo[0]);
			this.getClassComboBox().setModel(new DefaultComboBoxModel(fields));
			this.tableModel.setContent(fields);
			this.setSelectAll(true);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		updateSQL();
	}

	private void updateSQL() {
		this.getSqlTextArea().setText(this.getSQL());
	}

	private void setSelectAll(boolean b) {
		// this cell usually is the "ID", no use in DT
		tableModel.setValueAt(Boolean.FALSE, 0, 0);
		Boolean s = Boolean.valueOf(b);
		int row = tableModel.getRowCount();
		for (int i = 1; i < row; i++)
			tableModel.setValueAt(s, i, 0);
		tableModel.fireTableDataChanged();
	}

	private JComboBox getTableComboBox() {
		if (tableComboBox == null) {
			tableComboBox = new JComboBox();
			tableComboBox.addItemListener(new ItemListener() {
				public void itemStateChanged(ItemEvent e) {
					if (ItemEvent.DESELECTED != e.getStateChange())
						setSelectedTable(e.getItem().toString());
				}
			});
		}
		return tableComboBox;
	}

	private JComboBox getClassComboBox()
	{
		if( classComboBox == null )
		{
			classComboBox = new JComboBox();
			classComboBox.addItemListener( new ItemListener(){
				@Override
				public void itemStateChanged( ItemEvent e )
				{
					if( ItemEvent.SELECTED == e.getStateChange() )
						updateSQL();
				}
			} );
		}
		return classComboBox;
	}

	private JTable getFieldTable() {
		if (fieldTable == null) {
			fieldTable = new JTable(tableModel);
			fieldTable.setComponentPopupMenu(new TablePopup());
		}
		return fieldTable;
	}

	private JButton getOkButton()
	{
		if( okButton == null )
		{
			okButton = new JButton();
			okButton.setText( "OK" );
			okButton.addActionListener( new ActionListener(){
				@Override
				public void actionPerformed( ActionEvent e )
				{
					dispose();
				}
			} );
		}
		return okButton;
	}

	private void initialize()
	{
		this.setSize( 500, 500 );
		this.setModal( true );
		this.setDefaultCloseOperation( JDialog.DISPOSE_ON_CLOSE );
		this.setContentPane( getPane() );
		// -------------------------------
		this.tableModel.addContentChangedListener( new ChangeListener(){
			@Override
			public void stateChanged( ChangeEvent e )
			{
				updateSQL();
			}
		} );
	}

	private JPanel getPane() {
		if (pane == null) {
			GridBagConstraints gridBagConstraints21 = new GridBagConstraints();
			gridBagConstraints21.insets = new Insets(0, 0, 12, 0);
			gridBagConstraints21.weighty = 1;
			gridBagConstraints21.weightx = 3;
			gridBagConstraints21.gridwidth = 2;
			gridBagConstraints21.fill = GridBagConstraints.BOTH;
			gridBagConstraints21.gridx = 0;
			gridBagConstraints21.gridy = 3;
			GridBagConstraints gridBagConstraints12 = new GridBagConstraints();
			gridBagConstraints12.insets = new Insets(0, 0, 6, 0);
			gridBagConstraints12.weighty = 3;
			gridBagConstraints12.gridx = 0;
			gridBagConstraints12.gridwidth = 2;
			gridBagConstraints12.fill = GridBagConstraints.BOTH;
			gridBagConstraints12.weightx = 1;
			gridBagConstraints12.gridy = 2;
			GridBagConstraints gridBagConstraints6 = new GridBagConstraints();
			gridBagConstraints6.gridx = 0;
			gridBagConstraints6.fill = GridBagConstraints.HORIZONTAL;
			gridBagConstraints6.weightx = 10.0;
			gridBagConstraints6.gridwidth = 2;
			gridBagConstraints6.gridy = 4;
			GridBagConstraints gridBagConstraints5 = new GridBagConstraints();
			gridBagConstraints5.gridx = 0;
			gridBagConstraints5.fill = GridBagConstraints.BOTH;
			gridBagConstraints5.gridwidth = 2;
			gridBagConstraints5.weightx = 10.0;
			gridBagConstraints5.weighty = 10.0;
			gridBagConstraints5.gridy = 3;
			GridBagConstraints gridBagConstraints4 = new GridBagConstraints();
			gridBagConstraints4.fill = GridBagConstraints.HORIZONTAL;
			gridBagConstraints4.gridy = 1;
			gridBagConstraints4.weightx = 1.0;
			gridBagConstraints4.insets = new Insets(0, 6, 6, 0);
			gridBagConstraints4.gridx = 1;
			GridBagConstraints gridBagConstraints3 = new GridBagConstraints();
			gridBagConstraints3.gridx = 0;
			gridBagConstraints3.insets = new Insets(0, 0, 6, 0);
			gridBagConstraints3.anchor = GridBagConstraints.WEST;
			gridBagConstraints3.gridy = 1;
			classLabel = new JLabel();
			classLabel.setText("Class");
			GridBagConstraints gridBagConstraints1 = new GridBagConstraints();
			gridBagConstraints1.fill = GridBagConstraints.HORIZONTAL;
			gridBagConstraints1.gridy = 0;
			gridBagConstraints1.weightx = 1.0;
			gridBagConstraints1.insets = new Insets(0, 6, 6, 0);
			gridBagConstraints1.gridx = 1;
			GridBagConstraints gridBagConstraints = new GridBagConstraints();
			gridBagConstraints.gridx = 0;
			gridBagConstraints.anchor = GridBagConstraints.WEST;
			gridBagConstraints.insets = new Insets(0, 0, 6, 0);
			gridBagConstraints.gridy = 0;
			tableLabel = new JLabel();
			tableLabel.setText("Table");
			pane = new JPanel();
			pane.setLayout(new GridBagLayout());
			pane.setBorder(BorderFactory.createEmptyBorder(12, 12, 12, 12));
			pane.add(tableLabel, gridBagConstraints);
			pane.add(getTableComboBox(), gridBagConstraints1);
			pane.add(classLabel, gridBagConstraints3);
			pane.add(getClassComboBox(), gridBagConstraints4);
			// pane.add( getGluePane(), gridBagConstraints5 );
			pane.add(getFieldPane(), gridBagConstraints12);
			pane.add(getButtonsPane(), gridBagConstraints6);
			pane.add(getSqlPane(), gridBagConstraints21);
		}
		return pane;
	}

	private JScrollPane getFieldScrollPane() {
		if (fieldScrollPane == null) {
			fieldScrollPane = new JScrollPane();
			fieldScrollPane.setViewportView(getFieldTable());
		}
		return fieldScrollPane;
	}

	private JPanel getButtonsPane() {
		if (buttonsPane == null) {
			FlowLayout flowLayout = new FlowLayout();
			flowLayout.setHgap(0);
			flowLayout.setVgap(0);
			buttonsPane = new JPanel();
			buttonsPane.setLayout(flowLayout);
			buttonsPane.add(getOkButton(), null);
		}
		return buttonsPane;
	}

	/**
	 * This method initializes sqlScrollPane
	 * 
	 * @return javax.swing.JScrollPane
	 */
	private JScrollPane getSqlScrollPane() {
		if (sqlScrollPane == null) {
			sqlScrollPane = new JScrollPane();
			sqlScrollPane.setViewportView(getSqlTextArea());
		}
		return sqlScrollPane;
	}

	/**
	 * This method initializes sqlTextArea
	 * 
	 * @return javax.swing.JTextArea
	 */
	private JTextArea getSqlTextArea() {
		if (sqlTextArea == null) {
			sqlTextArea = new JTextArea();
			sqlTextArea.setEditable(false);
			sqlTextArea.setLineWrap(true);
			sqlTextArea.setWrapStyleWord(true);
		}
		return sqlTextArea;
	}

	/**
	 * This method initializes fieldPane
	 * 
	 * @return javax.swing.JPanel
	 */
	private JPanel getFieldPane() {
		if (fieldPane == null) {
			fieldPane = new JPanel();
			fieldPane.setLayout(new BorderLayout());
			fieldPane.setBorder(BorderFactory.createTitledBorder("Training Set"));
			fieldPane.add(getFieldScrollPane());
		}
		return fieldPane;
	}

	/**
	 * This method initializes sqlPane
	 * 
	 * @return javax.swing.JPanel
	 */
	private JPanel getSqlPane() {
		if (sqlPane == null) {
			sqlPane = new JPanel();
			sqlPane.setBorder(new TitledBorder(null, "SQL", TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, null, null));
			sqlPane.setLayout(new BorderLayout());
			sqlPane.add(getSqlScrollPane());
		}
		return sqlPane;
	}

	private class TablePopup extends JPopupMenu {
		public TablePopup()
		{
			ActionBuilder selectAll = new ActionBuilder( "Select All" );
			selectAll.setActionListener( new ActionListener(){
				@Override
				public void actionPerformed( ActionEvent e )
				{
					all( true );
				}
			} );
			ActionBuilder unselectAll = new ActionBuilder( "Unselect All" );
			unselectAll.setActionListener( new ActionListener(){
				@Override
				public void actionPerformed( ActionEvent e )
				{
					all( false );
				}
			} );
			this.add( selectAll );
			this.add( unselectAll );
		}

		private void all(boolean select) {
			setSelectAll(select);
		}
	}
}
